package com.orifine.dao;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.ResultSet;
import java.util.HashMap;
import java.util.Map;

import javax.sql.DataSource;

import com.orifine.dao.parser.SelectAsParser;
import com.orifine.dao.parser.SqlOgnlParser;

public class DaoProxy implements InvocationHandler {
	private DataSource dataSource;
	private Object daoMapper;
	private Map<Method, DaoModel> daoMethodMap = new HashMap<Method, DaoModel>(); 
	
	public DaoProxy(Class<?> daoClass, DataSource dataSource){
		this.dataSource = dataSource;
		
		try {
			this.daoMapper = Class.forName(daoClass.getName()+"Mapper").newInstance();
		} catch (ClassNotFoundException e) {
		} catch (InstantiationException e) {
			e.printStackTrace();
			throw new RuntimeException(daoClass.getName()+"Mapper需要无参默认的构造方法", e.fillInStackTrace());
		} catch (IllegalAccessException e) {
			e.printStackTrace();
			throw new RuntimeException(daoClass.getName()+"Mapper需要无参默认的构造方法", e.fillInStackTrace());
		}
		
		for(Method daoMethod : daoClass.getMethods()){
			Method mapperMethod = null;
			try {
				mapperMethod = this.daoMapper.getClass().getMethod(daoMethod.getName(), daoMethod.getParameterTypes());
			} catch (SecurityException e) {
				e.printStackTrace();
				throw new RuntimeException(e.getMessage(), e.fillInStackTrace());
			} catch (NoSuchMethodException e) {
			}
			
			DaoModel daoModel = new DaoModel(daoMethod, mapperMethod);
			daoMethodMap.put(daoMethod, daoModel);
		}
	}
	
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		
		DaoModel daoModel = daoMethodMap.get(method);
		if(daoModel == null){
			return method.invoke(this, args);
		} else {
			switch(daoModel.getType()){
			case SELECT:
			{
				String simpleSql = getSqlTemplate(daoModel, args);
				String querySql = SelectAsParser.parse(simpleSql);
				String finalSql = SqlOgnlParser.parse(querySql, daoModel.getDirectory(args), args);
				ResultSet resultSet = dataSource.getConnection().createStatement().executeQuery(finalSql);
				
				ResultModel resultModel = new ResultModel(resultSet);
				
				if(ResultModel.class.isAssignableFrom(method.getReturnType())){
					return resultModel;
				} else {
					return resultModel.get(method.getReturnType());
				}
			}
			case INSERT:
			{
				String simpleSql = getSqlTemplate(daoModel, args);
				String finalSql = SqlOgnlParser.parse(simpleSql, daoModel.getDirectory(args), args);
				if(method.getReturnType() == void.class){
					return void.class.newInstance();
				} else if(method.getReturnType() == boolean.class || method.getReturnType() == Boolean.class){
					int size = dataSource.getConnection().createStatement().executeUpdate(finalSql);
					return size != 0;
				} else {
					System.out.println(finalSql);
					return dataSource.getConnection().createStatement().executeUpdate(finalSql);
				}
			}
			case UPDATE:
			{
				String simpleSql = getSqlTemplate(daoModel, args);
				String finalSql = SqlOgnlParser.parse(simpleSql, daoModel.getDirectory(args), args);
				if(method.getReturnType() == void.class){
					return void.class.newInstance();
				} else if(method.getReturnType() == boolean.class || method.getReturnType() == Boolean.class){
					int size = dataSource.getConnection().createStatement().executeUpdate(finalSql);
					return size != 0;
				} else {
					return dataSource.getConnection().createStatement().executeUpdate(finalSql);
				}
			}
			case DELETE:
			{
				String simpleSql = getSqlTemplate(daoModel, args);
				String finalSql = SqlOgnlParser.parse(simpleSql, daoModel.getDirectory(args), args);
				if(method.getReturnType() == void.class){
					return void.class.newInstance();
				} else if(method.getReturnType() == boolean.class || method.getReturnType() == Boolean.class){
					int size = dataSource.getConnection().createStatement().executeUpdate(finalSql);
					return size != 0;
				} else {
					return dataSource.getConnection().createStatement().executeUpdate(finalSql);
				}
			}
			case INVOKE:
			{
				return method.invoke(daoMapper, args);
			}
			case NULL:
			default:
				throw new RuntimeException("没有找到可识别的SQL语句类别，可以使用注解或Mapper的Sql生成策略");
			}
		}
	}
	
	private String getSqlTemplate(DaoModel daoModel, Object[] args) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException{
		if(daoModel.getMapperMethod() != null && daoModel.getMapperMethod().getReturnType() != void.class){
			return daoModel.getMapperMethod().invoke(daoMapper, args).toString();
		} else {
			return daoModel.getValue();
		}
	}
}
